package org.example.springboot.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.example.springboot.utils.JwtUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.PrintWriter;

@Slf4j
public class UserAuthInterceptor implements HandlerInterceptor {
  private final String CUSTOM_HEADER_NAME;

  public UserAuthInterceptor(final String authHeaderName) {
    this.CUSTOM_HEADER_NAME = authHeaderName;
  }

  /**
   * 拦截器
   *
   * @param request  请求
   * @param response 响应
   * @param handler  处理器
   * @return 是否通过
   */
  @SneakyThrows
  @Override
  public boolean preHandle(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
    if (request.getRequestURI().contains("/login") ||
        request.getRequestURI().contains("/logout") ||
        request.getRequestURI().endsWith(".ico")) {
      return true;
    }
    // get a token from http headers.
    String token = request.getHeader(CUSTOM_HEADER_NAME);
    if (token == null) {
      writeResponseStream(response, "Token must not null, please ensure '%s' in your headers".formatted(CUSTOM_HEADER_NAME));
      return false;
    }

    if (JwtUtils.invalidateOrExpiredToken(token)) {
      writeResponseStream(response, "This jwt-token has expired/invalidated");
      return false;
    }

    if (!JwtUtils.validateToken(request.getHeader(CUSTOM_HEADER_NAME))) {
      writeResponseStream(response, "This jwt-token is invalid");
      return false;
    }

    return true;
  }

  @SneakyThrows
  private void writeResponseStream(@NonNull HttpServletResponse response, String responseStr) {
    PrintWriter writer = response.getWriter();
    writer.write(new ObjectMapper()
        .writeValueAsString(ResponseEntity.unprocessableEntity().body(responseStr)));
    writer.flush();
    writer.close();
  }
}
